#include "config.h"
#include "log.h"

namespace sylar
{
ConfigVarBase::ptr Config::LookupBase(const std::string& name)
{
    RWMutexType::ReadLock lock(GetMutex());
    auto it = GetDatas().find(name);
    if(it != GetDatas().end()) return it->second;
    return nullptr;
}

static void ListAllMember(const std::string& prefix,
                    const YAML::Node& node,
                    std::list<std::pair<std::string, const YAML::Node>>& output)
{
    if(prefix.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678")
            != std::string::npos) {
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "Config invalid name: " << prefix << " : " << node;
        return;
    }

    output.push_back(std::make_pair(prefix, node));

    if(node.IsMap())
    {
        for(auto it = node.begin()
            ;it != node.end(); ++it)
        {
            ListAllMember(prefix.empty() ? it->first.Scalar():prefix+'.'+it->first.Scalar()
            ,it->second
            ,output);
        }
    }

}

void Config::LoadFromYaml(const YAML::Node& root)
{
    std::list<std::pair<std::string, const YAML::Node>> all_node;
    ListAllMember("", root, all_node);

    for(auto& p:all_node)
    {
        std::string key = p.first;
        if(key.empty()) continue;
        
        std::transform(key.begin(), key.end(), key.begin(), ::tolower);

        ConfigVarBase::ptr it = LookupBase(key);
        if(it)
        {
            if(p.second.IsScalar())
            {
                it->fromString(p.second.Scalar());
            }
            else
            {
                std::stringstream ss;
                ss << p.second;
                it->fromString(ss.str());
            }
        }
    }
}

void Config::Visit(std::function<void(ConfigVarBase::ptr)> cb){
    RWMutexType::ReadLock lock(GetMutex());
    ConfigVarMap& m = GetDatas();
    for(auto it = m.begin();
            it != m.end(); ++it){
                cb(it->second);
            }
}

}